package com.example.a05;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.type.MethodMetadata;
import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
import org.springframework.core.type.classreading.MetadataReader;

import java.io.IOException;
import java.util.Set;

public class AtBeanPostProcessor implements BeanFactoryPostProcessor {

    /**
     * 梳理流程：<br/>
     * 首先读取 Config.class 的一些元数据信息，读取到之后，再进一步获取到被 @Bean 注解标注的方法信息，
     * 开始遍历，遍历的时候，针对每一个方法生成一个 BeanDefinition，
     * 将来方法名就作为 bean 的名字，BeanDefinition 需要指定工厂方法是谁，是哪个 bean 的方法
     * 这些都指定好了，然后注册到容器中
     * <br/>
     * 注意：还有对 @Bean 注解属性做解析
     */
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
        try {
            // // 创建缓存元数据读取工厂，用于读取类的元数据
            CachingMetadataReaderFactory factory = new CachingMetadataReaderFactory();
            // 不走类加载，效率比反射高 ---> 就是只解析字节码不加载类

            MetadataReader reader = factory.getMetadataReader(new ClassPathResource("com/example/a05/Config.class")); // 读取了配置类信息
            // 获取配置类中所有被@Bean注解的方法的元数据
            Set<MethodMetadata> methods = reader.getAnnotationMetadata().getAnnotatedMethods(Bean.class.getName());// 拿到所有被 @Bean 标注的方法的信息
            for (MethodMetadata method : methods) {
                System.out.println(method);
                // 获取方法的initMethod属性，即初始化方法的名称
                String initMethod = method.getAnnotationAttributes(Bean.class.getName()).get("initMethod").toString();

                BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition();
                builder.setFactoryMethodOnBean(method.getMethodName(), "config");
                // 对于构造方法的参数还有对于工厂方法的参数，想自动装配的话，选择的装配模式是这个 ---> AUTOWIRE_CONSTRUCTOR
                builder.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_CONSTRUCTOR);
                // 如果配置了初始化方法，将其设置到Bean定义中
                if (!initMethod.isEmpty()) { // 配置了初始化方法，就把初始化方法名字set进去
                    builder.setInitMethodName(initMethod);
                }
                AbstractBeanDefinition beanDefinition = builder.getBeanDefinition();
                if (configurableListableBeanFactory instanceof DefaultListableBeanFactory beanFactory) {
                    beanFactory.registerBeanDefinition(method.getMethodName(), beanDefinition);
                }
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
}
